eslint-plugin-importのno-extraneous-dependenciesがYarn PnPでうまく動作しないとき
tl;dr
code:.eslintrc.js
module.exports = {
...
settings: {
...
"import/internal-regex": /^@types\//,
"import/external-module-folders": ".yarn"
}
...
}
ESLintのプラグインであるeslint-plugin-importはno-extraneous-dependenciesというルールを定義している。これは非常に便利で、["error", { devDependencies: false }]と書くことでdependenciesに入っているパッケージを使うことを強制できる。
プロダクションに入るコードはdependenciesしか使ってないぞということを強制できるので、安心して{npm,yarn} install --productionしたりnpm pruneしたりできる
しかしこのルール、yarnのPnPを使うとうまく動かず、一切エラーを報告してくれない。
なんで?
実装みる
config: plugin:import/typescript
import/external-module-foldersってなに?
moduleが"external"であるかの判定に使ってるらしい
https://github.com/benmosher/eslint-plugin-import#importexternal-module-folders
no-extraneous-dependenciesの実装にあった https://github.com/benmosher/eslint-plugin-import/blob/72b9c3da5d30c39a4dcb677c7a46d2ddae8aca7e/src/rules/no-extraneous-dependencies.js#L135-137
code:js
if (importType(name, context) !== 'external') {
return;
}
判定条件は?
import/external-module-foldersを使ってるとこ
https://github.com/benmosher/eslint-plugin-import/blob/72b9c3da5d30c39a4dcb677c7a46d2ddae8aca7e/src/core/importType.js#L39
code:importType.js
function isExternalPath(name, settings, path, packagePath) {
const internalScope = (settings && settings'import/internal-regex');
if (internalScope && new RegExp(internalScope).test(name)) {
return false;
}
if (!path || relative(packagePath, path).startsWith('..')) {
return true;
}
const folders = (settings && settings'import/external-module-folders') || 'node_modules';
return folders.some((folder) => {
const folderPath = nodeResolve(packagePath, folder);
const relativePath = relative(folderPath, path);
return !relativePath.startsWith('..');
});
}
要するにそこ起点で解決したパスの親になれるものを選べばいいらしい
$ yarn node
require.resolve("react") --> /home/tosuke/.../.yarn/cache/react-npm-0.0.0-experimental-2bf4805e4-b45e82adb7-90db4fd2b7.zip/node_modules/react/index.js
.yarn/cacheにしようと思ったが、virtual directoryとして.yarn/__virtual__が指定されてるので.yarnにする
うごいた
続編
eslint-import-resolver-typescriptを使ってると、@types(DefinitelyTyped)系のパッケージをimportしてることにされてエラーになる
@typesはdevDepsなので
PnPでなければexternal-module-foldersにnode_modules/@typesを追加して解決している
eslint-plugin-import/typescript.js at 72b9c3da5d30c39a4dcb677c7a46d2ddae8aca7e · benmosher/eslint-plugin-import · GitHub
バッドノウハウにも程があるだろ
なんでこんなことになってるのかと言うと、この挙動が回避不可能だから
eslint-import-resolver-typescript/index.ts at 38dba0b66b9348c1ff61fc5d5b5207fecfd76c29 · alexgorbatchev/eslint-import-resolver-typescript · GitHub
なんでだよ
internal-regexという設定がeslint-plugin-importにあるので、これで無理やりextraneous-dependenciesの判定から外す
"import/internal-regex": /^@types\//